package com.icw.configuration.web.interceptor.apiproxy;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.Advisor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.icw.configuration.ConstSettings;
import com.icw.decoupling.defi.proxy.RestfulApiProxy;
import com.icw.resource.inner.entity.IcwPerm;
import com.icw.utility.IcwUtils;
import com.icw.utility.PoEntityHelper;

@Configuration
public class PermissionInterceptor {

	@Bean
	public Advisor verifyPermPoint() throws Exception {
		return IcwUtils.cutInterface(invocation -> {
			if (isExclude(invocation)) {
				// skip
			} else {
				String resourceName = IcwUtils.findArgs(invocation.getArguments(), String.class);
				String action = invocation.getMethod().getName();
				String route = PoEntityHelper.concatRoute(resourceName, action);
				IcwPerm perm = PoEntityHelper.findPermByRoute(route);
				if (perm != null) {
					Map<String, Object> params = IcwUtils.castMap(invocation.getArguments()[1]);
					Map<String, Object> ctx = new LinkedHashMap<>(PoEntityHelper.apiContext());
					PoEntityHelper.limitsParams(perm, params, ctx);
				} else if (isPublicAction(invocation) || IcwUtils.isAdmin()) {
					// skip
				} else {
					throw ConstSettings.NO_PERMISSION;
				}
			}
			String action = invocation.getMethod().getName();
			if ("post".equals(action) || "patch".equals(action)) {
				String resourceName = IcwUtils.findArgs(invocation.getArguments(), String.class);
				Class<?> entityClass = ConstSettings.LRsrcEntityMap.get(resourceName);
				Map<String, Object> params = IcwUtils.castMap(invocation.getArguments()[1]);
				PoEntityHelper.fillParams(entityClass, params);
			}
		}, RestfulApiProxy.class, ConstSettings.FIRST_ORDER);
	}

	private static boolean isExclude(MethodInvocation invocation) throws Exception {
		String action = invocation.getMethod().getName();
		return "exists".equals(action);
	}

	private static boolean isPublicAction(MethodInvocation invocation) throws Exception {
		String action = invocation.getMethod().getName();
		if (!String.class.isInstance(invocation.getArguments()[0])) {
			return false;
		} else {
			String resourceName = (String) invocation.getArguments()[0];
			Set<String> actionSet = PoEntityHelper.getResourcePublicActionMap().get(resourceName);
			return (actionSet != null && actionSet.contains(action));
		}
	}
}
